// Express应用主入口文件
// 该文件负责初始化Express应用、配置中间件、设置路由和启动服务器

// 引入Express框架，用于创建Web应用
// express: Node.js的Web应用框架，提供路由、中间件等功能
const express = require('express');

// 引入multer中间件，用于处理文件上传
// multer: Node.js中间件，专门用于处理multipart/form-data格式的文件上传
const multer = require('multer');

// 引入数据库连接和测试函数
// sequelize: Sequelize实例，用于数据库操作
// testConnection: 测试数据库连接的函数
// syncModels: 同步数据库模型的函数
const { sequelize, testConnection, syncModels } = require('./db');

// 创建Express应用实例
// app: Express应用实例对象，是整个后端应用的核心
const app = express();

// ==================== 中间件引入 ====================
// 引入安全中间件（包括HTTP头安全和API限流）
// securityHeaders: 设置安全HTTP头，防止XSS、点击劫持等攻击
// apiLimiter: API请求频率限制，防止恶意请求攻击
const { securityHeaders, apiLimiter } = require('./middleware/security');

// 引入CORS中间件（处理跨域请求）
// cors: 跨域资源共享中间件，解决前后端分离开发中的跨域问题
const cors = require('cors');

// // 引入日志中间件（记录请求日志）
// // requestLogger: 记录HTTP请求日志，便于调试和监控
// const { requestLogger } = require('./middleware/logger');

// 引入统一响应处理中间件
// 为响应对象添加success、error等方法，实现响应格式统一化
const responseHandler = require('./middleware/responseHandler');

// 引入统一错误处理中间件
// 捕获并处理应用中的各种错误，提供统一的错误响应格式
const errorHandler = require('./middleware/errorHandler');

// ==================== 文件上传配置 ====================
// 配置multer中间件用于处理文件上传
// multer.diskStorage: 磁盘存储引擎，将文件存储到服务器磁盘
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    // 确保uploads目录存在
    // fs: Node.js文件系统模块，用于文件操作
    const fs = require('fs');
    const dir = 'uploads/';
    // 检查目录是否存在，如果不存在则递归创建
    if (!fs.existsSync(dir)){
      fs.mkdirSync(dir, { recursive: true });
    }
    // 回调函数，第一个参数是错误信息，第二个参数是存储路径
    cb(null, dir);
  },
  filename: function (req, file, cb) {
    // 设置文件名：字段名+时间戳+原始文件名
    // 生成唯一的时间戳后缀，防止文件名冲突
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    // 构造文件名：字段名-时间戳.文件扩展名
    cb(null, file.fieldname + '-' + uniqueSuffix + '.' + file.originalname.split('.').pop());
  }
});

// 创建multer实例
// multer: 文件上传中间件实例
const upload = multer({ 
  storage: storage, // 使用上面定义的存储配置
  // 限制文件大小为10MB
  // limits: 文件大小限制配置
  limits: {
    fileSize: 10 * 1024 * 1024 // 10MB = 10 * 1024 * 1024 bytes
  },
  // 文件过滤器，只允许Excel文件
  // fileFilter: 文件类型过滤器，控制允许上传的文件类型
  fileFilter: function (req, file, cb) {
    // 检查文件类型是否为Excel文件
    // 支持.xlsx和.xls两种Excel格式
    if (file.mimetype === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || 
        file.mimetype === 'application/vnd.ms-excel' ||
        file.originalname.endsWith('.xlsx') || 
        file.originalname.endsWith('.xls')) {
      // 允许上传该文件
      cb(null, true);
    } else {
      // 拒绝上传该文件，返回错误信息
      cb(new Error('只允许上传Excel文件(.xlsx, .xls)'));
    }
  }
});

// ==================== 中间件使用 ====================
// 使用安全头中间件，增强HTTP头安全
// 防止XSS攻击、点击劫持等安全问题
//app.use(securityHeaders);

// 使用API请求限制中间件，防止恶意请求
// 限制每个IP在15分钟内最多100次请求
//app.use(apiLimiter);

// // 使用日志中间件，记录所有请求信息
// // 包括请求方法、URL、状态码、响应时间等
// app.use(requestLogger);

// 使用CORS中间件，允许跨域请求
// 解决前后端分离开发中的跨域问题
// cors(): 跨域资源共享中间件，允许前端应用访问后端API
app.use(cors());

// 使用body解析中间件，解析JSON和URL编码的请求体
// 限制请求体大小为10MB，防止大文件上传攻击
// express.json(): 解析JSON格式的请求体
app.use(express.json({ limit: '10mb' }));
// express.urlencoded(): 解析URL编码格式的请求体
app.use(express.urlencoded({ extended: false, limit: '10mb' }));

// 使用统一响应处理中间件，为res对象添加success、error等方法
// 实现响应格式统一化，便于前端处理响应数据
// responseHandler: 统一响应处理中间件
app.use(responseHandler);

// ==================== JWT认证中间件 ====================
// JWT认证中间件，用于验证用户身份
// expressJWT: Express的JWT认证中间件
const { expressjwt: expressJWT } = require('express-jwt');
// 引入应用配置文件
const config = require('./config');

// 配置JWT中间件 - 临时禁用所有接口的验证
// secret: 用于签名和验证JWT的密钥
// algorithms: 使用的算法
// issuer: JWT签发者
// 注意：在生产环境中不应禁用认证
app.use(expressJWT({ 
  // 使用配置文件中的密钥
  secret: config.jwtSecretKey, 
  // 指定算法
  algorithms: [config.jwt.algorithm],
  // 指定签发者
  issuer: config.jwt.issuer
  // 临时排除所有路径，禁用认证
  // 仅用于开发和测试环境，生产环境必须启用认证
}).unless({ 
  path: [ 
    /\/.*/  // 匹配所有路径，临时禁用所有接口的认证
  ] 
}));

// ==================== 路由配置 ====================
// 引入并使用各个模块的路由
// userRouter: 用户认证路由（注册、登录等）
const userRouter = require('./router/user');              
// userinfoRouter: 用户信息路由（获取用户信息等）
const userinfoRouter = require('./router/userinfo');       
// customersRouter: 客户管理路由
const customersRouter = require('./router/customers');     
// productsRouter: 产品管理路由
const productsRouter = require('./router/products');       
// salesOrdersRouter: 销售订单路由
const salesOrdersRouter = require('./router/salesOrders'); 
// productCategoriesRouter: 产品分类路由
const productCategoriesRouter = require('./router/productCategories'); 
// suppliersRouter: 供应商管理路由
const suppliersRouter = require('./router/suppliers');     
// courierCompaniesRouter: 快递公司管理路由
const courierCompaniesRouter = require('./router/courierCompanies');     
// expressInfoRouter: 快递信息管理路由
const expressInfoRouter = require('./router/expressInfo');     
// deliveryOrdersRouter: 发货单管理路由
const deliveryOrdersRouter = require('./router/deliveryOrders');     

// 挂载路由到对应的路径
// /api: 用户认证相关接口，如注册、登录
app.use('/api', userRouter);                    
// /my: 用户个人信息相关接口
app.use('/my', userinfoRouter);                 
// /customers: 客户管理相关接口
app.use('/customers', customersRouter);         
// /products: 产品管理相关接口
app.use('/products', productsRouter);           
// /salesOrders: 销售订单相关接口
app.use('/salesOrders', salesOrdersRouter);     
// /productCategories: 产品分类相关接口
app.use('/productCategories', productCategoriesRouter); 
// /suppliers: 供应商管理相关接口
app.use('/suppliers', suppliersRouter);         
// /courier-companies: 快递公司管理相关接口
app.use('/courier-companies', courierCompaniesRouter);         
// /express-info: 快递信息管理相关接口
app.use('/express-info', expressInfoRouter);         
// /deliveryOrders: 发货单管理相关接口
app.use('/deliveryOrders', deliveryOrdersRouter);         

// ==================== 错误处理 ====================
// 使用统一错误处理中间件，处理所有未捕获的错误
// 必须放在所有路由之后，确保能捕获到所有错误
// errorHandler: 统一错误处理中间件
app.use(errorHandler);

// ==================== 服务器启动 ====================
// 监听3007端口，启动服务器
// 使用async/await处理异步操作
// app.listen(): 启动HTTP服务器并监听指定端口
app.listen(3007, async function() {
  try {
    // 测试数据库连接
    // 验证数据库配置是否正确
    // testConnection(): 测试数据库连接的异步函数
    await testConnection();
    
    // 根据环境变量决定是否同步数据库模型
    // 在开发环境中可以自动同步模型到数据库
    // syncModels(): 同步数据库模型的异步函数
    if (process.env.SYNC_DATABASE === 'true') {
      await syncModels();
    }
    
    // 输出服务器启动成功信息
    console.log(`🚀 服务器运行在 http://127.0.0.1:3007`);
  } catch (error) {
    // 输出服务器启动失败信息
    console.error('服务器启动失败:', error);
  }
});